package cc.linker.steplink.crm.task;

import cc.linker.steplink.crm.commons.constant.ContentConstant;
import cc.linker.steplink.crm.commons.constant.WcPayConstant;
import cc.linker.steplink.crm.commons.http.HttpService;
import cc.linker.steplink.crm.commons.lock.RedisLock;
import cc.linker.steplink.crm.commons.model.SystemProperties;
import cc.linker.steplink.crm.dao.CustomerDao;
import cc.linker.steplink.crm.dao.PreciseDao;
import cc.linker.steplink.crm.dao.SelfDao;
import cc.linker.steplink.crm.domain.Precise;
import cc.linker.steplink.crm.merchant.dao.NewMallDao;
import cc.linker.steplink.crm.merchanth5.service.common.SmsService;
import cc.linker.steplink.crm.response.GlobalException;
import cc.linker.steplink.crm.service.CustomerService;
import cc.linker.steplink.crm.service.EmailService;
import cc.linker.steplink.crm.service.ITemplateMessageService;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.util.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 精准推送
 *
 * @author wuyue
 */

@Slf4j
@Configuration
public class PrecisionPush {

    private static final String NICK_NAME = "【昵称】";
    private static final String DEFAULT_NAME = "用户";

    private static final String WX_PUSH_RESULT = "SCRM:PrecisionPush:WX_PUSH_RESULT";

    private static final String WX_PUSH_WAIT_LIST = "SCRM:PrecisionPush:WX_PUSH_WAIT_LIST";

    // 微信群发文章超时设置，单位秒
    private static final long WX_PUSH_WAIT_TIMEOUT = 3 * 3600;

    @Value("${system.scrm.wxpushurl}")
    private String url;

    @Value("${system.scrm.wxMatrix}")
    private String wxurl;

    @Value("${system.scrm.defimg}")
    private String defimg;

    @Autowired
    private CustomerDao customerDao;
    @Autowired
    private PreciseDao preciseDao;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private SelfDao selfDao;
    @Autowired
    private NewMallDao newMallDao;
    @Autowired
    private HttpService httpService;
    @Autowired
    private ITemplateMessageService tempMsgService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private SystemProperties systemProperties;
    @Autowired
    private SmsService smsService;
    @Autowired
    private EmailService emailService;


    public void sendTemplate(String msg) {
        try {
            if (StringUtils.isEmpty(msg)) {
                return;
            }
            Map<String, String> parse = (Map) JSON.parse(msg);
            if (null != parse) {
                if ("payment".equals(parse.get("sendType"))) {
                    tempMsgService.sendPayMsg(parse);
                }
                if ("delivery".equals(parse.get("sendType"))) {
                    tempMsgService.sendDeliveryMsg(parse);
                }
            }
        } catch (Exception e) {
            LOGGER.error("sendTemplate", e);
        }
    }

    @Async
    @RedisLock(value = "PrecisionPush")
    @Scheduled(cron = "7 */5 * * * ?")
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void doPush() {
        // 获取待推送列表 taskId, groupId, content, pushType 1-智能推送 2-自定义推送, orgId
        List<Map<String, Object>> toBePushedList = preciseDao.getToBePushedList();
        this.type1(toBePushedList);
    }
    public void type1(List<Map<String, Object>> toBePushedList) {
        if (toBePushedList == null || toBePushedList.size() == 0) {
            return;
        }
        // 先修改所有任务的状态
        List<String> taskIdList = toBePushedList.stream()
                .map(x -> (String) x.get("taskId"))
                .collect(Collectors.toList());
        preciseDao.changeStatusByList(taskIdList);

        // 遍历待推送列表,map:数据库中单条记录
        for (Map<String, Object> map : toBePushedList) {
            String taskId = (String) map.get("taskId");
            if (StringUtils.isEmpty(taskId)) {
                LOGGER.info("任务ID为空");
                continue;
            }
            String orgId = (String) map.get("orgId");
            // 获取推送content(json:List<Map>)
            String contentStr = (String) map.get("content");
            // content内容 contentType内容分类 sendType推送渠道逗号拼接（带排序） sendWay1 一个渠道；2 所有渠道
            Map content = (Map) JSON.parse(contentStr);
            if (content == null || content.size() == 0) {
                LOGGER.info("内容不正确,taskId = [{}]", taskId);
                cancel(taskId);
                continue;
            }
            content.put("orgId", orgId);
            content.put("taskId", taskId);
            // 获取待推送的分群id
            String groupId = (String) map.get("groupId");
            if (StringUtils.isEmpty(groupId)) {
                LOGGER.info("获取分群ID失败,taskId = [{}]", taskId);
                cancel(taskId);
                continue;
            }
            // 根据分群id获取分群规则(非实时)
            List<String> strings = customerService.listCustomerByGroupId(groupId);
            // 实时
//            List<String> strings = new ArrayList<>();
//            String[] split = groupId.split(",");
//            for (String s : split) {
//                Map<String, String> groupInclude = groupDao.getGroupInclude(s);
//                String include = groupInclude.get("include");
//                String orgId = groupInclude.get("orgId");
            // 根据分群规则获取用户id列表
//                List<String> list = customerService.countGroup(include, orgId);
//                strings.addAll(list);
//            }
            if (strings.size() <= 0) {
                LOGGER.info("无匹配客户,taskId = [{}]", taskId);
                // 改变状态
                cancel(taskId);
                continue;
            }
            LOGGER.info("精准推送开始执行：taskId = [{}], groupId = [{}], content = [{}]", taskId, groupId, JSON.serialize(content));
            int total = strings.size();
            // 推送方式 1-智能推送 2-自定义推送
            Integer pushType = (Integer) map.get("pushType");
            // 1：微信客服消息，2：微信群发消息，3：短信 若pushType=1,则按照123执行
            // 用于记录推送成功数
            int count = 0;
            int polPlan = 0;
            int polTouch = 0;
            int wxPlan = 0;
            int wxTouch = 0;
            int smsPlan = 0;
            int smsTouch = 0;
            try {
                if (pushType == 1) {
                    // todo 智能推送没有邮箱
                    // 123
                    Map<String, Object> result1 = this.push1(content, strings);
                    if (result1 == null) {
                        cancel(taskId);
                        continue;
                    }
                    polPlan = strings.size();
                    polTouch = (Integer) result1.get("count");
                    count += polTouch;
                    List list1 = (List) result1.get("list");
                    if (list1 != null && list1.size() > 0) {
                        wxPlan = list1.size();
                        //2020-03-30 修改大于1W用户的群发
                        int coun = wxPlan/10000;
                        if(coun>0){
                            for (int i = 0; i <= coun; i++) {
                                int startIdx = i * 10000;
                                int endIdx = i * 10000 + 10000;
                                if (endIdx >= wxPlan) {
                                    endIdx = wxPlan;
                                }
                                List<String> plans = list1.subList(startIdx, endIdx);
                                this.push2(content, plans);
                            }
                        }else{
                            this.push2(content, list1);
                        }
                    }
                } else if (pushType == 2) {
                    // 自定义
                    String sendType = (String) content.get("sendType");
                    String sendWay = (String) content.get("sendWay");
                    String[] split = sendType.split(",");
                    for (String s : split) {
                        Map<String, Object> result = null;
                        switch (s) {
                            case "1":
                                result = this.push1(content, strings);
                                polPlan = strings.size();
                                polTouch = (Integer) result.get("count");
                                if (!"2".equals(sendWay)) {
                                    // 不是全部渠道，全部渠道要统计
                                    count += polTouch;
                                }
                                break;
                            case "2":
//                                this.push2(content, strings);
//                                wxPlan = strings.size();
                                wxPlan = strings.size();
                                //2020-03-30 修改大于1W用户的群发
                                int coun = wxPlan/10000;
                                if(coun>0){
                                    for (int i = 0; i <= coun; i++) {
                                        int startIdx = i * 10000;
                                        int endIdx = i * 10000 + 10000;
                                        if (endIdx >= wxPlan) {
                                            endIdx = wxPlan;
                                        }
                                        List<String> plans = strings.subList(startIdx, endIdx);
                                        this.push2(content, plans);
                                    }
                                }else{
                                    this.push2(content, strings);
                                }
                                break;
                            case "3":
//                            result = this.push3(content, strings);
//                            smsPlan = strings.size();
//                            smsTouch = (Integer) result.get("count");
                                break;
                            case "4":{
                                // 发送邮箱
                                // 1.获取邮箱号 并以逗号分隔
                                List<String> emailList =  customerDao.getEmailsByCustomerIds(strings,null);

                                emailList = Optional.ofNullable(emailList)
                                        .orElse(new ArrayList<>())
                                        .stream()
                                        .filter(each -> StrUtil.isNotBlank(each))
                                        .collect(Collectors.toList());

                                // 2.发送邮箱
                                String msg = String.valueOf(content.get("content"));
                                String taskName = String.valueOf(map.get("taskName"));
                                if(null != emailList && 0 < emailList.size()){
                                    for (int i = 0; i < emailList.size(); i++) {
                                        emailService.sendEmailToAddress(emailList.get(i),msg,taskName);
                                    }
                                }

                            }
                            default:
                                break;
                        }
                        if ("2".equals(sendWay)) {
                            // 全部渠道
                            continue;
                        }
                        if (result != null) {
                            List list = (List) result.get("list");
                            if (list != null && list.size() > 0) {
                                strings = list;
                            } else {
                                break;
                            }
                        } else {
                            cancel(taskId);
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                LOGGER.error("精准推送执行异常", e);
                throw GlobalException.build("精准推送执行异常");
            } finally {
                // 推送完毕，改变表中状态为已执行,记录人群数和触达数
                Map<String, Object> map1 = new HashMap<>();
                map1.put("taskId", taskId);
                map1.put("count", count);
                map1.put("total", total);
                map1.put("polPlan", polPlan);
                map1.put("polTouch", polTouch);
                map1.put("wxPlan", wxPlan);
                map1.put("wxTouch", wxTouch);
                map1.put("smsPlan", smsPlan);
                map1.put("smsTouch", smsTouch);
                preciseDao.changeStatus(map1);
            }
        }
    }

    /**
     * 客服消息
     */
    private Map<String, Object> push1(Map content, List<String> strings) {
        int count = 0;
        List<String> unTouchedList = new ArrayList<>();
        // 给接口的参数
        Map<String, Object> requestMap = new HashMap<>();

        String msg = (String) content.get("content");
        if (StringUtils.isEmpty(msg)) {
            LOGGER.info("推送内容不能为空");
            return null;
        }
        String type = (String) content.get("contentType");
        if ("img".equals(type)) {
            requestMap.put("action", "activeReply");
            requestMap.put("type", "image");
            requestMap.put("val", msg);
        } else if ("text".equals(type)) {
            requestMap.put("action", "activeReply");
            requestMap.put("type", "text");
            requestMap.put("val", msg);
        } else if ("article".equals(type)) {
            // 客服消息发article
            requestMap.put("action", "replayNews");

            Map parse = (Map) JSON.parse(msg);
            requestMap.put("desc", parse.get("newsSummary"));
            requestMap.put("image", StringUtils.isEmpty(parse.get("newsCoverFirst")) ? defimg : parse.get("newsCoverFirst"));
            requestMap.put("title", parse.get("newsName"));
            requestMap.put("url", parse.get("url"));
        } else if("editor".equals(type)){
                return null;
        } else {
            LOGGER.info("内容类型不符");
            return null;
        }

        for (String string : strings) {
            Map<String, Object> identification = customerDao.getIdentificationByCustomerId(string);
//            Map<String, Object> identification = customerInfoIdpDao.getIdentification(string);
            if (identification == null) {
                LOGGER.info("获取用户信息失败");
                continue;
            }
            String customerName = (String) identification.get("customerName");
            String idpToken = (String) identification.get("token");
//            String idpToken = (String) identification.get("idpToken");
            String idpOpenid = (String) identification.get("openId");
//            String idpOpenid = (String) identification.get("idpOpenid");
            if (StringUtils.isEmpty(idpToken) || StringUtils.isEmpty(idpOpenid)) {
                continue;
            }
            requestMap.put("token", idpToken);
            requestMap.put("openid", idpOpenid);
            String old = (String) requestMap.get("val");
            if ("text".equals(type)) {
                String val = (String) requestMap.get("val");
                if (val.contains(NICK_NAME)) {
                    val = val.replaceAll(NICK_NAME, customerName);
                    requestMap.put("val", val);
                }
            }
            // 调用wx接口，发送消息
            Map<String, String> postParam = new HashMap<>();
            postParam.put("Content-Type", "application/json;charset=UTF-8");
            String s;
//            LOGGER.info("push1_request===" + JSON.serialize(requestMap));
            try {
                s = httpService.doPost(url, JSON.serialize(requestMap), postParam);
            } catch (URISyntaxException | IOException e) {
                LOGGER.warn("调用异常");
                continue;
            }
            if ("text".equals(type)) {
                requestMap.put("val", old);
            }
            Map res = (Map) JSON.parse(s);
            Integer errcode = (Integer) res.get("errcode");
            if (errcode == 200) {
                count++;
            } else {
                unTouchedList.add(string);
            }
            LOGGER.info("res = " + s);
            try {
                Thread.sleep(50);
            } catch (InterruptedException ignored) {

            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("count", count);
        map.put("list", unTouchedList);
        return map;
    }

    /**
     * 微信群发消息
     */
    @Async
    public void push2(Map content, List<String> strings) {
        if (strings.size() < 2) {
            LOGGER.warn("群发人数不能少于2人,customerId==={}", strings);
            return;
        }
//        if (strings.size() > 10000) {
//            // todo 群发不能超过10000人(待优化)
//            strings = strings.subList(0, 10000);
//        }
        // 给接口的参数
        Map<String, Object> requestMap = new HashMap<>();

        String msg = (String) content.get("content");
        String taskId = (String) content.get("taskId");
        if (StringUtils.isEmpty(msg)) {
            LOGGER.info("推送内容不能为空");
            return;
        }
        boolean isArticle = false;
        String type = (String) content.get("contentType");
        if ("img".equals(type)) {
            requestMap.put("action", "sendImageMassMessage");
            requestMap.put("val", msg);
        } else if ("text".equals(type)) {
            requestMap.put("action", "sendTextMassMessage");
            if (msg.contains(NICK_NAME)) {
                msg = msg.replaceAll(NICK_NAME, DEFAULT_NAME);
            }
            requestMap.put("val", msg);
        } else if ("article".equals(type)) {
            isArticle = true;
        } else {
            LOGGER.info("内容类型不符");
            return;
        }
        String orgId = (String) content.get("orgId");
        String token = preciseDao.getTokenByOrgId(orgId);
        requestMap.put("token", token);
        String join = org.apache.commons.lang.StringUtils.join(strings, ",");
        List<String> openIdsList = preciseDao.getOpenIdsByCustomerIdsAndToken(join, token);

        if (isArticle) {
//            StringBuilder stringBuilder = new StringBuilder(openIds);
            try {
                Map<String, Object> map = new HashMap<>();
                map.put("content", content);
                map.put("taskId", taskId);
                String s = this.sendNews(map, openIdsList, token);
                if (StringUtils.isEmpty(s)) {
                    Map<String, Object> redisMap = new HashMap<>();
                    redisMap.put("content", map);
                    redisMap.put("openIds", openIdsList);
                    redisMap.put("token", token);
                    // 设置过期时间
                    long l = System.currentTimeMillis() / 1000;
                    redisMap.put("timeout", l);
                    stringRedisTemplate.opsForHash().put(WX_PUSH_WAIT_LIST, taskId, JSON.serialize(redisMap));
                } else {
                    this.saveResult(s, taskId);
                }
            } catch (Exception e) {
                LOGGER.warn("接口调用异常");
            }
            return;
        }

        String openIds = org.apache.commons.lang.StringUtils.join(openIdsList, ",");
        requestMap.put("openids", openIds);

        String result;
        try {
            String serialize = JSON.serialize(requestMap);
            LOGGER.info("push2_request===[{}]", serialize);
            result = httpService.doPost(url, serialize, WcPayConstant.JSON);
        } catch (URISyntaxException | IOException e) {
            LOGGER.warn("接口调用异常");
            return;
        }
        LOGGER.info("push2_result===[{}],taskId===[{}]", result, taskId);
        this.saveResult(result, taskId);
    }

    private void saveResult(String result, String taskId) {
        Precise precise = new Precise();
        precise.setTaskId(taskId);
        precise.setWxPushResult(result);
        Map parse = (Map) JSON.parse(result);
        Map data = (Map) parse.get("data");
        String msgId = data.get("msg_id").toString();
        if (StringUtils.isEmpty(msgId)) {
            LOGGER.error("精准推送taskId===[{}],获取msgId失败", taskId);
        } else {
            precise.setMsgId(msgId);
            stringRedisTemplate.opsForHash().put(WX_PUSH_RESULT, taskId, msgId);
        }
        preciseDao.updateByPrimaryKeySelective(precise);
    }

    /**
     * 短信(暂无)
     */
    private Map<String, Object> push3(Map content, List<String> strings) {
        if (true) {
            LOGGER.warn("短信暂不支持");
            return null;
        }

        int count = 0;
        List<String> unTouchedList = new ArrayList<>();
        String join = org.apache.commons.lang.StringUtils.join(strings, ",");
        String customerPhones = preciseDao.getCustomerPhonesByCustomerIds(join);
//        String url = wcPayProperties.getSmsurl() + WcPayConstant.SMS_SEND_MESSAGE;


        Map<String, Object> reqMap = new HashMap<>();
        reqMap.put("businessType", "9005");
        reqMap.put("mobilNumber", customerPhones);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("product", content.get("msg"));
        reqMap.put("params", JSON.serialize(paramMap));
//        reqMap.put("plantName", "STEPLINK");
        String result = smsService.sendMsg("", reqMap);
//        try {
//            result = httpService.doPost(url, reqMap);
//        } catch (URISyntaxException | IOException e) {
//            LOGGER.warn("接口调用异常");
//            return null;
//        }
        Map parse = (Map) JSON.parse(result);
        Integer rt = (Integer) parse.get("rt");

        if (rt == 1) {
            // 返回未发送成功的手机号码，以逗号分隔
            String con = (String) parse.get("con");
            if (!StringUtils.isEmpty(con)) {
                String customerIds = preciseDao.getCustomerIdsByCustomerPhones(con);
                String[] split = customerIds.split(",");
                Collections.addAll(unTouchedList, split);
            }
            count = strings.size() - unTouchedList.size();
        } else if (rt == 0) {
            unTouchedList = strings;
        }

        Map<String, Object> map = new HashMap<>();
        map.put("count", count);
        map.put("list", unTouchedList);
        return map;
    }

    private void cancel(String taskId) {
        Map<String, Object> map1 = new HashMap<>();
        map1.put("taskId", taskId);
        map1.put("count", 0);
        map1.put("total", 0);
        preciseDao.changeStatus(map1);
    }

    @RedisLock(value = "wxPrecisionPush")
    @Scheduled(cron = "0 */5 * * * ?")
    public void doWxPush() {
        // 获取待推送列表
        List<Map<String, Object>> list = preciseDao.getWxToBePushedList();
        if (list != null && list.size() > 0) {
            for (Map<String, Object> data : list) {
                try {
                    String token = newMallDao.getTokenByOrgId(data.get("orgId"));
                    Map co = (Map) JSON.parse(data.get("content").toString());
                    String groupId = data.get("groupId").toString();
                    String taskId = data.get("taskId").toString();

//                    StringBuilder openidIds = new StringBuilder();
                    List<HashMap<String, Object>> personList = selfDao.getNeedPushUserListByGroupId(groupId);


                    if (null == personList || personList.size() < 2) {
                        //查不到人，或人数小于2，不符合群发条件，取消任务
                        taskCancel(taskId, "查不到人，或人数小于2，不符合群发条件，取消任务");
                        continue;
                    }

                    List<String> wxOpenidList = personList.stream()
                            .map(x -> (String) x.get("WX_OPENID"))
                            .distinct()
                            .collect(Collectors.toList());

//                    for (HashMap<String, Object> per : personList) {
//                        if (!StringUtils.isEmpty(per.get("WX_OPENID"))) {
//                            if (openidIds.length() > 0) {
//                                openidIds.append(",").append(per.get("WX_OPENID").toString());
//                            } else {
//                                openidIds.append(per.get("WX_OPENID").toString());
//                            }
//                        }
//                    }
//                    String[] split = openidIds.toString().split(",");
                    if (wxOpenidList.size() < 2) {
//                        LOGGER.info("群发消息至少要2个openids");
                        taskCancel(taskId, "群发消息至少要2个openids");
                        continue;
                    }
                    String sendRes = "";
                    if ("news".equals(co.get("contentType").toString())) {
                        sendRes = sendNews(data, wxOpenidList, token);
                    }
                    if ("text".equals(co.get("contentType").toString())) {
                        String openidIds = org.apache.commons.lang.StringUtils.join(wxOpenidList, ",");
                        sendRes = sendText(data, new StringBuilder(openidIds), token);
                    }
                    if (!"".equals(sendRes)) {
                        Map parse = (Map) JSON.parse(sendRes);
                        if ("0".equals(parse.get("errcode").toString())) {
                            Map msgData = (Map) parse.get("data");
                            taskDone(taskId, msgData.get("msg_id").toString(), token);
                        } else {
                            taskCancel(taskId, sendRes);
                        }
                    }

                } catch (Exception e) {
                    LOGGER.error("精准推送catch错误:", e);
                }
            }
        }
    }

    private String sendText(Map data, StringBuilder openidIds, String token) throws IOException, URISyntaxException {
        Map co = (Map) JSON.parse(data.get("content").toString());
        Map<String, String> pushdata = new HashMap<>();
        pushdata.put("action", "sendTextMassMessage");
        pushdata.put("openids", openidIds.toString());
        pushdata.put("val", co.get("content").toString());
        pushdata.put("token", token);
        Map<String, String> postParam = new HashMap<>();
        postParam.put("Content-Type", "application/json;charset=UTF-8");
        JSONObject jsonObject = (JSONObject) JSONArray.toJSON(pushdata);
        return httpService.doPost(url, jsonObject.toJSONString(), postParam);
    }

    private String sendNews(Map data, List<String> openidIds, String token) throws IOException, URISyntaxException {
        LOGGER.info("sendNews,data===[{}],openIds===[{}],token===[{}]", data.toString(), openidIds, token);
        String taskId = data.get("taskId").toString();
        String mediaId = getMediaByTaskId(taskId);
        if (StringUtils.isEmpty(mediaId)) {
            uploadNews(taskId, token, data.get("content").toString());
            return "";
        }

        Map<String, Object> pushdata = new HashMap<>();
        Map<String, Object> res = new HashMap<>();
        Map<String, Object> mpnews = new HashMap<>();
        mpnews.put("media_id", mediaId);
        res.put("touser", openidIds);
        res.put("mpnews", mpnews);
        res.put("msgtype", "mpnews");
        res.put("send_ignore_reprint", 1);
        pushdata.put("val", res);
        pushdata.put("token", token);
        pushdata.put("action", "sendNewsMassMessage");
        Map<String, String> postParam = new HashMap<>();
        postParam.put("Content-Type", "application/json;charset=UTF-8");
        JSONObject jsonObject = (JSONObject) JSONArray.toJSON(pushdata);
        LOGGER.info("sendNews,send,taskId===[{}],param===[{}]", taskId, jsonObject.toJSONString());
        return httpService.doPost(wxurl + "/idp.php", jsonObject.toJSONString(), postParam);
    }

    public String getMediaByTaskId(String taskId) throws IOException, URISyntaxException {
        String mediaId = stringRedisTemplate.opsForValue().get("sendNewsTaskIdMediaId" + taskId);
        if (!StringUtils.isEmpty(mediaId)) {
            return mediaId;
        }
        Map<String, Object> pushdata = new HashMap<>();
        pushdata.put("ApprovalID", taskId);
        Map<String, String> postParam = new HashMap<>();
        postParam.put("Content-Type", "application/json;charset=UTF-8");
        JSONObject jsonObject = (JSONObject) JSONArray.toJSON(pushdata);
        String postres = httpService.doPost(wxurl + "/index.php?s=/home/MassSend/get_media_id", jsonObject.toJSONString(), postParam);
        LOGGER.info("getMediaByTaskId===[{}],result===[{}]", taskId, postres);
        if (null != postres) {
            List<Map> res = (List) JSON.parse(postres);
            if (null != res && res.size() > 0) {
                Map ma = res.get(0);
                if (null != ma.get("media_id")) {
                    stringRedisTemplate.opsForValue().set("sendNewsTaskIdMediaId" + taskId, ma.get("media_id").toString());
                    stringRedisTemplate.expire("sendNewsTaskIdMediaId" + taskId, 60, TimeUnit.MINUTES);
                    return ma.get("media_id").toString();
                } else {
                    if (null != ma.get("result_data")) {
                        Map resultData = (Map) JSON.parse(ma.get("result_data").toString());
                        if (!StringUtils.isEmpty(resultData.get("errcode").toString())) {
                            taskCancel(taskId, postres);
                            stringRedisTemplate.opsForHash().delete(WX_PUSH_WAIT_LIST, taskId);
                        }
                    }
                }
            }
        }
        return "";
    }

    public void taskDone(String taskId, String msgId, String token) {
        Map<String, Object> param = new HashMap<>();
        param.put("status", "1");
        param.put("taskId", taskId);
        param.put("msgId", msgId);
        preciseDao.updateWxPush(param);
    }

    public void taskCancel(String taskId, String result) {
        Map<String, Object> param = new HashMap<>();
        param.put("status", "2");
        param.put("taskId", taskId);
        param.put("wxPushResult", result);
        preciseDao.updateWxPush(param);
    }

    private void uploadNews(String taskId, String token, String content) throws IOException, URISyntaxException {
        Map postres = (Map) JSON.parse(content);
        if (!"news".equals(postres.get("contentType")) && !"article".equals(postres.get("contentType"))) {
            return;
        }
        if ("article".equals(postres.get("contentType"))) {
            LOGGER.info("article.equals(postres.get(contentType))");
            String contentStr = (String) postres.get("content");
            Map parse = (Map) JSON.parse(contentStr);
            List<Map> list = new ArrayList<>();
            list.add(parse);
            postres.put("content", list);
        }
        LOGGER.info("postres===" + JSON.serialize(postres));
        List arts = (List) postres.get("content");
        List<Map<String, Object>> li = new ArrayList<>();
        Map<String, Object> res = new HashMap<>();
        for (Object ar : arts) {
            Map ma = (Map) ar;
            String articleId = ma.get("id").toString();
            Map articleDetail = this.getArticleDetail(articleId);
            Map<String, Object> data = new HashMap<>();
            data.put("title", articleDetail.get("newsName"));
            data.put("content", articleDetail.get("newsContent"));
            data.put("digest", articleDetail.get("newsSummary"));
            List nc = (List) articleDetail.get("newsCover");
            String thumbUrl;
            if (null == nc || nc.size() == 0) {
                thumbUrl = defimg;
            } else {
                thumbUrl = nc.get(0).toString();
            }
            data.put("thumb_url", thumbUrl);
            li.add(data);
        }
        res.put("articles", li);
        res.put("ApprovalID", taskId);
        res.put("token", token);

        Map<String, String> postParam = new HashMap<>();
        postParam.put("Content-Type", "application/json;charset=UTF-8");
        JSONObject jsonObject = (JSONObject) JSONArray.toJSON(res);
        String s = httpService.doPost(wxurl + "/index.php?s=/home/MassSend/uploadnews", jsonObject.toJSONString(), postParam);
        LOGGER.info("uploadNews,taskId===[{}],result===[{}]", taskId, s);
    }

    private Map getArticleDetail(String articleId) throws GlobalException, IOException, URISyntaxException {
        String url = systemProperties.getSync().getContentUrl() + ContentConstant.GET_ARTICLE_DETAIL;
        Map<String, Object> param = new HashMap<String, Object>();
        Map<String, Object> resData = new HashMap<String, Object>();
        param.put("newsId", articleId);
        JSONObject jsonObject = (JSONObject) JSONArray.toJSON(param);
        String postres = httpService.doPost(url, jsonObject.toJSONString(), ContentConstant.JSON_HEADER);
        if (null != postres) {
            Map res = (Map) JSON.parse(postres);
            if ("200".equals(res.get("code").toString())) {
                resData.put("newsName", ((Map) res.get("data")).get("newsName"));
                resData.put("createTime", ((Map) res.get("data")).get("createTime"));
                resData.put("newsSummary", ((Map) res.get("data")).get("newsSummary"));
                resData.put("newsContent", ((Map) res.get("data")).get("newsContent"));
                resData.put("headPicUrl", ((Map) res.get("data")).get("headPicUrl"));
                resData.put("newsCover", ((Map) res.get("data")).get("newsCover"));
            } else {
                throw GlobalException.build("请求失败");
            }
        } else {
            throw GlobalException.build("请求失败");
        }
        return resData;
    }

    /**
     * 处理微信群发结果，更新触达人数
     */
    @Async
    @Scheduled(cron = "5 */3 * * * ?")
    public void updatePushResult() {
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(WX_PUSH_RESULT);
        if (entries == null || entries.size() == 0) {
            return;
        }
        entries.forEach((x, y) -> {
            String taskId = (String) x;
            String msgId = (String) y;
            Map<String, Object> reqMap = new HashMap<>();
            reqMap.put("action", "getMassRes");
            reqMap.put("msgId", msgId);
            Map<String, Object> precise = preciseDao.getPrecise(taskId);
            if (precise == null) {
                stringRedisTemplate.opsForHash().delete(WX_PUSH_RESULT, x);
                return;
            }
            String orgId = (String) precise.get("orgId");
            String token = preciseDao.getTokenByOrgId(orgId);
            reqMap.put("token", token);
            String res;
            try {
                res = httpService.doPost(url, JSON.serialize(reqMap), WcPayConstant.JSON);
            } catch (URISyntaxException | IOException e) {
                LOGGER.warn("接口调用异常");
                return;
            }
            Map parse = (Map) JSON.parse(res);
            Integer errcode = (Integer) parse.get("errcode");
            if (errcode == 200) {
                Map data = (Map) parse.get("data");
                String sentCount = (String) data.get("SentCount");
                Map<String, Object> map = new HashMap<>();
                map.put("taskId", taskId);
                map.put("sentCount", sentCount);
                preciseDao.updateWxTouchByTaskId(map);
                stringRedisTemplate.opsForHash().delete(WX_PUSH_RESULT, x);
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException ignored) {

            }
        });

    }

    /**
     * 群发文章消息，等待上传成功，发送
     */
    @Async
    @RedisLock(value = "gky_wxgrouppostarticle")
    @Scheduled(cron = "55 */3 * * * ?")
    public void wxGroupPostArticle() {
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(WX_PUSH_WAIT_LIST);
        entries.forEach((x, y) -> {
            String taskId = (String) x;
            String s = (String) y;
            Map parse = (Map) JSON.parse(s);
            Map content = (Map) parse.get("content");
            //noinspection unchecked
            List<String> openIds = (List) parse.get("openIds");
            String token = (String) parse.get("token");
            Integer timeout = (Integer) parse.get("timeout");
            try {
                long l = System.currentTimeMillis() / 1000;
                if (l - timeout > WX_PUSH_WAIT_TIMEOUT) {
                    stringRedisTemplate.opsForHash().delete(WX_PUSH_WAIT_LIST, x);
                }
                String result = this.sendNews(content, openIds, token);
                if (!StringUtils.isEmpty(result)) {
                    this.saveResult(result, taskId);
                    stringRedisTemplate.opsForHash().delete(WX_PUSH_WAIT_LIST, x);
                }
            } catch (Exception e) {
                LOGGER.error("群发消息发生异常", e);
            }

        });

    }
}

